
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Common/Support/Debug.h"


#include "Common/World/Point.h"
#include "Player/Formation.h"

const float FIELD_LENGTH = 104.0f;
const float FIELD_WIDTH = 68.0f;
const float DEFENCE_AREA = -30.0f;
const float ATTACK_AREA = 30.0f;

const float MID_DEF_X_DIST = 15.0f;
const float MID_OFF_X_DIST = -20.0f;
const float MID_MAX_X_DIST = 25.0f;
const float DEF_MAX_X_DIST = 60.0f;
const float DEF_MIN_X_DIST = 30.0f;

const float FOR_MAX_X_DIST_OUR = 30.0f;
const float FOR_MAX_X_DIST_THEIR = 24.0f;
const float FOR_MIN_X_DIST_OUR = 0.0f;
const float FOR_MIN_X_DIST_THEIR = 8.0f;

const float FOR_MAX_DEFENCE_X_POS = -4.0f;

const float HALF_FIELD_X_POS = 0.0f;
const float MIN_BORDER_X_POS = 10.0f;

Formation::Formation()
{
	FILE *f;
	char def, mid, atk, offset;
	float offset2;
	//07.03.05
	m_nDefUnits = 0;
	m_nMidUnits = 0;
	m_nForUnits = 0;
	m_mDefOffset = DEF_ORIGIN_DIST;
	m_mMidOffset = MID_ORIGIN_DIST;
	m_mForOffset = FOR_ORIGIN_DIST;
	
	this->ParseConfig();
	//
//	SetUnits(16, 2, 17);

	if ((f = fopen("formation.cfg", "r")) != NULL)
	{
		if (4 != fscanf(f, "%c%c%c%c", &def, &mid, &atk, &offset))
		{
			TXT("Zly format configu formacii, pouzivam default QCRN\n\n");
			SetUnits(16, 2, 17);
			SetUnitOffset(-30.0);
			fclose(f);
		}
		else
		{
			TXT("Formacia nacitana: %c%c%c%c\n\n", def, mid, atk, offset);
			SetUnits(def - 'A', mid - 'A', atk - 'A');
			offset2 = 2.0f*(offset-'A') - FIELD_LENGTH/2.0f;
			SetUnitOffset(offset2);
			fclose(f);
		}
	}
	else
	{
		TXT("Config formacii nenajdeny, pouzivam default QCRN\n\n");
		SetUnits(16, 2, 17);	
		SetUnitOffset(-30.0);
	}

	for( int i = 0; i < UNITS_COUNT; ++i ) {
		for( int j = 0; j < UNIT_MAX_PLAYERS; ++j ) {
			m_cUnits[i].m_cRelPos[j] = Point( UNDEF_POS, UNDEF_POS );
		}
	}
}


//nacita jeden riadok z konfiguracneho suboru
//ak sa podari, vrati true, inak false (ak je koniec suboru)
bool Formation::ReadConfigLine(FILE * file, char * parameter, char * values)
{
	char buffer[255];
	int i, j;

  //nacitanie riadka zo suboru do buffera
  i = 0;
  while (fread(&buffer[i], sizeof(char), 1, file) == 1 && buffer[i] != '\n')
    if (buffer[i] != '\r') i++;
  if (feof(file)) return false; //koniec suboru
  buffer[i] = '\0';

  if (i == 0)
  {
    parameter[0] = '\0';
    values[0] = '\0';
    return true;
  }

	//parameter
	i = 0;
	while(buffer[i] != '<')
    i++;
	j = i+1;
	i = 0;
	while(buffer[j] != '>')
	{
		parameter[i] = buffer[j];
		i++;
		j++;
	}
	parameter[i] = '\0';

	//values
  j++; //bolie sme na '>', posunuli sme sa doprava
  //najdeme prvy znak iny nez medzera/tabulator
	while ((buffer[j] == ' ') || (buffer[j] == '\t'))
  	j++;
  if (buffer[j] != '\0')
  {
    //najdeme znak '<'
    i = 0;
    while (buffer[j] != '<')
    {
      values[i] = buffer[j];
      i++;
      j++;
    }
  } else
    i = 0;
  values[i] = '\0';

  return true;
}

//////////////////////////////////////////////////////////////////////////////
// void Formation::ParseConfig()
// ---------------------------------------------------------------------------
// Description:
//		nacitanie subformacii zo suboru units.xml
//
// ---------------------------------------------------------------------------
// Parameters:
//
//////////////////////////////////////////////////////////////////////////////
void Formation::ParseConfig()
{
	FILE * file;
	char parameter[50], values[200];
  char * value;

  int cvgX, cvgY;
	float relPosX, relPosY;
	int iPlayer = 0;
	int name=-1; //nazov danej formacie
	bool bNewUnit = false;
	Unit * _unit = NULL;

  file = fopen("units.xml", "r" );

	if (file != NULL)
  {
		// citaj riadky v subore az kym nedorazis na koniec
		//TXTN("--------------------Nacitanie formacii--------------------");
    while (ReadConfigLine(file, parameter, values))
    {
      //nacitanie prvej hodnoty z values
      value = strtok(values, " \t");

			//nastavenie atributov pre dane parametre a ich hodnoty
			if (strcmp(parameter,"unit") == 0)
			{
				_unit = new Unit();
				cvgX = cvgY = 0;
				bNewUnit = true;
			} else
			if (strcmp(parameter,"name") == 0)
			{
				if (bNewUnit == true)
				{
          iPlayer = 0;
					_unit->m_name = atoi(value);
					UnitList[_unit->m_name] = _unit; // uloz danu subformaciu do pola smernikov s indexom ID subformacie
					bNewUnit = false;
				}
			} else
			if (strcmp(parameter,"type") == 0)
			{
				if (_unit != NULL)
				{
					_unit->m_type = atoi(value);
					switch (_unit->m_type)
					{
						case 0:
							m_nDefUnits++;
							break;
						case 1:
							m_nMidUnits++;
							break;
						case 2:
							m_nForUnits++;
							break;
					}
				}
			} else
			if (strcmp(parameter,"width") == 0)
			{
				if (_unit != NULL)
					_unit->m_nWidth = atoi(value);
			} else
			if (strcmp(parameter,"height") == 0)
			{
				if (_unit != NULL)
					_unit->m_nHeight = atoi(value);
			} else
			if (strcmp(parameter,"scale") == 0)
			{
				if (_unit != NULL)
					_unit->m_fScale = (float)atof(value);
			} else
			if (strcmp(parameter,"playerCount") == 0)
			{
				if (_unit != NULL)
					_unit->m_nPlayerCount = atoi(value);
			} else
			if (strcmp(parameter,"relPosX") == 0)
				relPosX = (float)atof(value); else
			if (strcmp(parameter,"relPosY") == 0)
				relPosY = (float)atof(value); else
			if (strcmp(parameter,"range") == 0)
			{
				if (_unit != NULL)
				{
					_unit->m_cRelPos[iPlayer] =  Point( relPosX, relPosY );
					_unit->m_cRange[iPlayer] = (float)atof(value);
					iPlayer++;
				}
			} else
			if (strcmp(parameter,"coverage") == 0)
			{
				if (_unit != NULL)
				{
					//nacitaj prvu hodnotu
					_unit->m_fCoverage[cvgX][cvgY] = (float) atof(value);
					cvgY++;
					while ((value = strtok(NULL, " \t")) != NULL)
					{
						_unit->m_fCoverage[cvgX][cvgY] = (float)atof(value);
						cvgY++;  
					}
					cvgY = 0;
					cvgX++;
				}
			}
    }

    fclose(file);
  }
	TXTN("FORMATIONS LOADED");
}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetUnitsCount(int type)
// ---------------------------------------------------------------------------
// Description:
//		vrati pocet subformacii
//
// ---------------------------------------------------------------------------
// Parameters:
//		int type (type = 1 - obrana, 2 - stred, 3 - utok, cislo != 1,2,3 - suma)
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetUnitsCount(int type)
{
	int count=0;
	switch (type)
	{
		case 1:
			count = m_nDefUnits;
			break;
		case 2:
			count = m_nMidUnits;
			break;
		case 3:
			count = m_nForUnits;
			break;
		default:
			count = m_nDefUnits + m_nMidUnits + m_nForUnits;
	}
	return count;
}

//////////////////////////////////////////////////////////////////////////////
// Point Formation::GetPlayerPosInUnit(int nFormation, int nPlayer)
// ---------------------------------------------------------------------------
// Description:
//		vrati x-ovu a y-ovu poziciu hraca v ramci subformacie
//		nPlayer - je cislo hraca v ramci jednotky, nie celej subformacie
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormation
//		int nPlayer
//
//////////////////////////////////////////////////////////////////////////////
Point Formation::GetPlayerPosInUnit(int nFormation, int nPlayer)
{
	Unit * _unit;

	_unit = UnitList[nFormation];
	return _unit->m_cRelPos[nPlayer];
}

//////////////////////////////////////////////////////////////////////////////
// float Formation::GetUnitWidth(int nFormation)
// ---------------------------------------------------------------------------
// Description:
//		vrati sirku subformacie v metroch
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormation
//
//////////////////////////////////////////////////////////////////////////////
float Formation::GetUnitWidth(int nFormation)
{
	Unit * _unit;

	_unit = UnitList[nFormation];
	return _unit->m_nWidth*_unit->m_fScale;
}

//////////////////////////////////////////////////////////////////////////////
// Point Formation::GetUnitDimensions(int nFormation)
// ---------------------------------------------------------------------------
// Description:
//		vrati rozmery subformacie v pocte sektorov
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormation
//
//////////////////////////////////////////////////////////////////////////////
Point Formation::GetUnitDimensions(int nFormation)
{
	Unit * _unit;

	_unit = UnitList[nFormation];
	Point D;
	D.SetX((float)_unit->m_nHeight);
	D.SetY((float)_unit->m_nWidth);
	return D;
}

//////////////////////////////////////////////////////////////////////////////
// void Formation::GetUnitCoverage(int nFormation, float (* fCoverage)[10] )
// ---------------------------------------------------------------------------
// Description:
//		vrati dvojrozmerne pole pokrytia hracov danej subformacie 
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormation
//		float (* fCoverage)[10]
//
//////////////////////////////////////////////////////////////////////////////
void Formation::GetUnitCoverage(int nFormation, float (* fCoverage)[11] )
{
	int i,j;
	Unit * _unit;

	_unit = UnitList[nFormation];
	for (i=0; i < _unit->m_nHeight; i++)
		for (j=0; j < _unit->m_nWidth; j++)
			fCoverage[i][j] = _unit->m_fCoverage[i][j];
}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetPlayersCountInUnit(int nFormation)
// ---------------------------------------------------------------------------
// Description:
//		vrati pocet hracov v danej jednotke
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormation
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetPlayersCountInUnit(int nFormation)
{
	Unit * _unit;

	_unit = UnitList[nFormation];
	return _unit->m_nPlayerCount;
}

//////////////////////////////////////////////////////////////////////////////
// void Formation::SetUnitOffset(float offset, int type)
// ---------------------------------------------------------------------------
// Description:
//		nastavi offset danej subformacie
//
// ---------------------------------------------------------------------------
// Parameters:
//		int type -> 0 - defense, 1 - midfield, 2 - forward
//		float offset
//
//////////////////////////////////////////////////////////////////////////////
void Formation::SetUnitOffset(float offset, int type)
{
	switch(type)
	{
		case 0:
			m_mDefOffset = offset;
			break;
		case 1:
			m_mMidOffset = offset;
			break;
		case 2:
			m_mForOffset = offset;
			break;
	}
}

//////////////////////////////////////////////////////////////////////////////
// float Formation::GetUnitOffset(int nFormation)
// ---------------------------------------------------------------------------
// Description:
//		vrati offset danej subformacie
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormation
//
//////////////////////////////////////////////////////////////////////////////
float Formation::GetUnitOffset(int type)
{
	float offset = 0;
	switch(type)
	{
		case 1:
			offset = m_mDefOffset;
			break;
		case 2:
			offset = m_mMidOffset;
			break;
		case 3:
			offset = m_mForOffset;
			break;
	}
	return offset;
}

//////////////////////////////////////////////////////////////////////////////
// void Formation::SetUnits(int nDefUnitID, int nMidUnitID, int nForUnitID)
// ---------------------------------------------------------------------------
// Description:
//		nastavi ID aktualnych subformacii
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nDefUnitID, int nMidUnitID, int nForUnitID
//
//////////////////////////////////////////////////////////////////////////////
void Formation::SetUnits(int nDefUnitID, int nMidUnitID, int nForUnitID)
{
	m_nDefUnitID = nDefUnitID;
	m_nMidUnitID = nMidUnitID;
	m_nForUnitID = nForUnitID;
}

//////////////////////////////////////////////////////////////////////////////
// void Formation::GetUnits(int & nDefUnitID, int & nMidUnitID, int & nForUnitID)
// ---------------------------------------------------------------------------
// Description:
//		vrati ID aktualnych subformacii
//
// ---------------------------------------------------------------------------
// Parameters:
//		int & nDefUnitID, int & nMidUnitID, int & nForUnitID
//
//////////////////////////////////////////////////////////////////////////////
void Formation::GetUnits(int & nDefUnitID, int & nMidUnitID, int & nForUnitID)
{
	nDefUnitID = m_nDefUnitID;
	nMidUnitID = m_nMidUnitID;
	nForUnitID = m_nForUnitID;
}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetUnitFromRawUnit( int nPlayersCount, int nRawUnit )
// ---------------------------------------------------------------------------
// Description:
//		vrati index kontretnej jednotky pre dany pocet hracov v nej na zaklade 
//		vseobecneho rozlozenia - nRawUnit
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nPlayersCount
//		int nRawUnit
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetUnitFromRawUnit( int nPlayersCount, int nRawUnit )
{
	switch( nPlayersCount )
	{
		case 2 :
			// pre dvoch hracov ine rozostavenie nemame
			return UNIT_2_L;

		case 3 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
					case UNIT_TWO_LINES:
						return UNIT_3_L;

					case UNIT_CENTER_ATTACK:
					case UNIT_2LINES_ATTACK:
					case UNIT_STRONG_CENTER:
						return UNIT_3_V;

					case UNIT_CENTER_DEFENCE:
					case UNIT_2LINES_DEFENCE:
						return UNIT_3_OV;
				}
			}
			break;

		case 4 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
					case UNIT_TWO_LINES:
						return UNIT_4_L;

					case UNIT_CENTER_ATTACK:
					case UNIT_2LINES_ATTACK:
						return UNIT_4_V;

					case UNIT_CENTER_DEFENCE:
					case UNIT_2LINES_DEFENCE:
						return UNIT_4_OV;

					case UNIT_STRONG_CENTER:
						return UNIT_4_S;
				}
			}
			break;

		case 5 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
						return UNIT_5_L;

					case UNIT_CENTER_ATTACK:
					case UNIT_STRONG_CENTER:
						return UNIT_5_V;

					case UNIT_CENTER_DEFENCE:
						return UNIT_5_OV;

					case UNIT_TWO_LINES:
					case UNIT_2LINES_DEFENCE:
						return UNIT_5_23;

					case UNIT_2LINES_ATTACK:
						return UNIT_5_32;
				}
			}
			break;

		case 6 :
			{
				switch( nRawUnit ) {
					case UNIT_LINE:
					case UNIT_TWO_LINES:
						return UNIT_6_2L;

					case UNIT_CENTER_ATTACK:
					case UNIT_2LINES_ATTACK:
					case UNIT_STRONG_CENTER:
						return UNIT_6_V;

					case UNIT_CENTER_DEFENCE:
					case UNIT_2LINES_DEFENCE:
						return UNIT_6_OV;
				}
			}
			break;
	}

	// chyba 
	return UNIT_6_2L;
}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetPlayersRoleCount( int nFormationId, FormationRole eRole )
// ---------------------------------------------------------------------------
// Description:
//		vrati pocet hracov, ktori vo formacii nFormationId maju rolu eRole
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nFormationId
//		FormationRole eRole
//
//////////////////////////////////////////////////////////////////////////////
//int Formation::GetPlayersRoleCount( int nFormationId, FormationRole eRole )
//{
//	int ret_val = 0;
//
//	for( int i = 0; i < 11; ++i ) {
//		if ( m_eRole[nFormationId][i] == eRole ) {
//			++ret_val;
//		}
//	}
//
//	return ret_val;
//}

void Formation::Init( int nTeamSide, int nFormationId, int nDefUnit, int nMidUnit, int nForUnit )
{
	m_nTeamSide = nTeamSide;
	m_nFormationId = nFormationId;

	m_nDefUnitID = nDefUnit;
	m_nMidUnitID = nMidUnit;
	m_nForUnitID = nForUnit;
}

void Formation::InitRawUnits( int nTeamSide, int nFormationId, int nDefUnit, int nMidUnit, int nForUnit )
{
	m_nTeamSide = nTeamSide;
	m_nFormationId = nFormationId;

	m_nDefUnitID = nDefUnit; //GetUnitFromRawUnit( GetPlayersRoleCount( nFormationId, PR_Defensman ), nDefUnit );
	m_nMidUnitID = nMidUnit; //GetUnitFromRawUnit( GetPlayersRoleCount( nFormationId, PR_Midfielder ), nMidUnit );
	m_nForUnitID = nForUnit; //GetUnitFromRawUnit( GetPlayersRoleCount( nFormationId, PR_Forward ), nForUnit );;
}

//////////////////////////////////////////////////////////////////////////////
// FormationRole Formation::GetPlayerRole(int nPlayerId )
// ---------------------------------------------------------------------------
// Description:
//		vrati typ role hraca s danym cislom dresu
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nPlayerId 
//
//////////////////////////////////////////////////////////////////////////////
FormationRole Formation::GetPlayerRole(int nPlayerId )
{
	Unit * _unit;

	int nDefPlayers, nMidPlayers, nForPlayers;
	
	_unit = UnitList[m_nDefUnitID];
	nDefPlayers = _unit->m_nPlayerCount;
	_unit = UnitList[m_nMidUnitID];
	nMidPlayers = _unit->m_nPlayerCount;
	_unit = UnitList[m_nForUnitID];
	nForPlayers = _unit->m_nPlayerCount;

	if (nPlayerId == 0)
			return PR_GoalKeeper;
	if (nPlayerId <= (nDefPlayers))
		return PR_Defensman;
	if (nPlayerId <= (nDefPlayers + nMidPlayers ))
		return PR_Midfielder;
	if (nPlayerId <= (nDefPlayers + nMidPlayers + nForPlayers))
		return PR_Forward;

	return PR_Forward;
}

//obsolete
//FormationRole Formation::GetPlayerRole( int nTeamSide, int nPlayerId )
//{
//	return m_eRole[m_nFormationId][nPlayerId];
//}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetUnitIndex(int nPlayerId )
// ---------------------------------------------------------------------------
// Description:
//		vrati index hraca v ramci subformacie
//
// ---------------------------------------------------------------------------
// Parameters:
//		int nPlayerId 
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetUnitIndex(int nPlayerId )
{
	Unit * _unit;

	int nDefPlayers, nMidPlayers, nForPlayers;
	
	_unit = UnitList[m_nDefUnitID];
	nDefPlayers = _unit->m_nPlayerCount;
	_unit = UnitList[m_nMidUnitID];
	nMidPlayers = _unit->m_nPlayerCount;
	_unit = UnitList[m_nForUnitID];
	nForPlayers = _unit->m_nPlayerCount;

	if (nPlayerId <= (nDefPlayers))
		return nPlayerId - 1;
	if (nPlayerId <= (nDefPlayers + nMidPlayers))
		return nPlayerId - 1 - nDefPlayers;
	if (nPlayerId <= (nDefPlayers + nMidPlayers + nForPlayers ))
		return nPlayerId - 1 - nDefPlayers - nMidPlayers;

	return -1;
}

//obsolete 
//int Formation::GetUnitIndex( int nTeamSide, int nPlayerId )
//{
//	FormationRole eRole = GetPlayerRole( nTeamSide, nPlayerId );
//
//	int nDefCnt, nMidCnt;
//
//	nDefCnt = 0;
//	nMidCnt = 0;
//	int nFormationId = m_nFormationId;
//	
//	for( int index = 0; index < PLAYER_COUNT; ++index ) {
//		if ( m_eRole[nFormationId][index] == PR_Defensman ) {
//			++nDefCnt;
//		}
//
//		if ( m_eRole[nFormationId][index] == PR_Midfielder ) {
//			++nMidCnt;
//		}
//	}
//
//	switch( eRole ) {
//		case PR_GoalKeeper :
//			return -1;
//
//		case PR_Defensman :
//			return int(nPlayerId - 1 );
//
//		case PR_Midfielder :
//			return int(nPlayerId - 1 - nDefCnt );
//
//		case PR_Forward :
//			return int(nPlayerId - 1 - nDefCnt - nMidCnt );
//	}
//
//	return -1;
//}

//////////////////////////////////////////////////////////////////////////////
// int Formation::GetUnitId( int nTeamSide, FormationRole eRole )
// ---------------------------------------------------------------------------
// Description:
//		vrati id subformacie pre danu rolu
//
// ---------------------------------------------------------------------------
// Parameters:
//		FormationRole eRole
//
//////////////////////////////////////////////////////////////////////////////
int Formation::GetUnitId(FormationRole eRole )
{
	switch( eRole ) {
		case PR_GoalKeeper :
			return -1;

		case PR_Defensman :
			return m_nDefUnitID;

		case PR_Midfielder :
			return m_nMidUnitID;

		case PR_Forward :
			return m_nForUnitID;
	}

	return -1;
}

// obsolete
//int Formation::GetUnitId( int nTeamSide, FormationRole eRole )
//{
//	switch( eRole ) {
//		case PR_GoalKeeper :
//			return -1;
//
//		case PR_Defensman :
//			return m_nUnitDef;
//
//		case PR_Midfielder :
//			return m_nUnitMid;
//
//		case PR_Forward :
//			return m_nUnitFor;
//	}
//
//	return -1;
//}

Point Formation::GetPlayerPosition( int nTeamSide, int nPlayerId )
{
	FormationRole eRole = GetPlayerRole( nPlayerId );

	if ( eRole == PR_GoalKeeper ) {
		return GOALIE_POS;
	}
	
	m_dDefBallDist = 1.0;
	m_dMidBallDist = 1.0;
	m_dForBallDist = 1.0;

	Point cOriginPos = GetUnitPosition( nTeamSide, nPlayerId );

	switch( eRole ) {
		case PR_Defensman :            
			//cOriginPos = Point(cOriginPos.GetX() + (m_mDefOffset * m_dDefBallDist), cOriginPos.GetY());
			cOriginPos = Point((m_mDefOffset * m_dDefBallDist), cOriginPos.GetY());
			break;

		case PR_Midfielder :
            //cOriginPos = Point(cOriginPos.GetX() + (m_mMidOffset * m_dMidBallDist), cOriginPos.GetY());
			cOriginPos = Point((m_mDefOffset * m_dDefBallDist), cOriginPos.GetY());
			break;

		case PR_Forward :
            // = Point(cOriginPos.GetX() + (m_mForOffset * m_dForBallDist), cOriginPos.GetY());						
			cOriginPos = Point((m_mDefOffset * m_dDefBallDist), cOriginPos.GetY());
			break;
	}

	return cOriginPos;
}

// zmenene 18.03.05 
Point Formation::GetUnitPosition( int nTeamSide, int nPlayerId )
{	
	FormationRole eRole = GetPlayerRole(nPlayerId );
	
	if ( eRole == PR_GoalKeeper ) {
		return GOALIE_POS;
	}

	float width = UNIT_WIDTH;
	float scale = 1.0f;
	
	int nUnitIndex = GetUnitIndex(nPlayerId );
	int nUnitId = GetUnitId( eRole );
	
	//ASSERT( nUnitIndex >= 0 && nUnitIndex <= UNIT_MAX_PLAYERS );

	Unit * _unit;
	_unit = UnitList[nUnitId];
	Point ret_val = _unit->m_cRelPos[nUnitIndex];
	
	// uprav x-ovu suradnicu podla sirky jednotky
	ret_val.SetX(ret_val.GetX() * width); 
	ret_val.SetY(ret_val.GetY() * scale);
	
	return ret_val;
}

Point Formation::GetPlayerPosition( int nPlayerId, const Point& cBallPos )
{
	return GetPlayerPosition( m_nTeamSide, nPlayerId - 1, cBallPos, true, true );
}

Point Formation::GetPlayerPosition( int nTeamSide, int nPlayerId, const Point& cBallPos, bool followx, bool followy )
{
	//Point cOriginPos = m_cRelPos[nPlayerId];
	Point cOriginPos = GetPlayerPosition( 0, nPlayerId );
	//cOriginPos.GetX() *= m_nTeamSide;
	Point cBall = cBallPos;
	cBall.SetX( cBall.GetX() * m_nTeamSide);


	if ( followx ) 
	{
		cOriginPos = AdjustXPosition( nTeamSide, nPlayerId, cOriginPos, cBall );
		// uprav x-ovu suradnicu o posunutie v ramci jednotky
		Point originPos = GetUnitPosition( nTeamSide, nPlayerId );
		cOriginPos.SetX(originPos.GetX() + cOriginPos.GetX());

		// posun pozicie od krajov ihriska, v zmysle x-ovej osi
		if ( cOriginPos.GetX() > ( FIELD_LENGTH / 2.0f - MIN_BORDER_X_POS ) ) {
			cOriginPos.SetX( FIELD_LENGTH / 2.0f - MIN_BORDER_X_POS );
		}
		else {
			if ( cOriginPos.GetX() < ( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS ) ) {
				cOriginPos.SetX( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS );
			}
		}
	}

	if( followy ) 
	{
		cOriginPos = AdjustYPosition( nTeamSide, nPlayerId, cOriginPos, cBall );

	}

	cOriginPos.SetX(nTeamSide * cOriginPos.GetX());

	// 18.03.05 transformacia suradnic (pociatok: stred -> lavy horny roh)
	//cOriginPos.SetX(FIELD_LENGTH / 2.0f + cOriginPos.GetX());
	//cOriginPos.SetY(FIELD_WIDTH / 2.0f + cOriginPos.GetY());

	//Unit * _unit;

	/*for (int i = 0; i < 15; i++)
	{
		_unit = UnitList[i];
		TXTN("Name: %d x= %f y= %f range= %f ", _unit->m_name, _unit->m_cRelPos[0].GetX(), _unit->m_cRelPos[0].GetY(), _unit->m_cRange[0]);
		TXTN("Name: %d x= %f y= %f range= %f ", _unit->m_name, _unit->m_cRelPos[1].GetX(), _unit->m_cRelPos[1].GetY(), _unit->m_cRange[1]);
	}*/

	return cOriginPos;
}

Point Formation::AdjustXPosition( int nTeamSide, int nPlayerId, const Point& cOriginPos, const Point& cBallPos )
{
	Point ret_val;
	FormationRole player_role = GetPlayerRole( nPlayerId );

	switch( player_role ) {
		case PR_GoalKeeper:
			ret_val = cOriginPos;
			break;

		case PR_Defensman:
			ret_val = AdjustDefPositionX( cOriginPos, cBallPos );
			break;
			
		case PR_Midfielder:
			ret_val = AdjustMidPositionX( cOriginPos, cBallPos );
			break;
			
		case PR_Forward:
			ret_val = AdjustForPositionX( cOriginPos, cBallPos );
			break;
	}

	return ret_val; 
}

Point Formation::AdjustYPosition( int nTeamSide, int nPlayerId, const Point& cOriginPos, const Point& cBallPos )
{
	Point cRetVal = cOriginPos;
	float fLow = 0.1f;
	float fHi = 0.5f;

	if ( nTeamSide < 0 ) {
		nTeamSide = 0;
	}

	FormationRole eRole = GetPlayerRole( nPlayerId );
	int nUnitId = GetUnitId( eRole );
	int nMyIndex = GetUnitIndex( nPlayerId );
	
	Unit * _unit;
	_unit = UnitList[nUnitId];	
	int p_cnt = _unit->m_nPlayerCount;
	
	float scale = 1.0f;
	float power = 1.0f;
	switch( eRole ) {
		case PR_Defensman :
//			scale = PlayerConfig.ScaleYPosDef();
//			power = PlayerConfig.FollowYPowerDef();
            // GP
            scale = 0.5f;
            power = 1.25f;
			break;

		case PR_Midfielder :
//			scale = PlayerConfig.ScaleYPosMid();
//			power = PlayerConfig.FollowYPowerMid();
            // GP
            scale = 0.5f;
            power = 1.25f;
			break;

		case PR_Forward :
//			scale = PlayerConfig.ScaleYPosFor();
//			power = PlayerConfig.FollowYPowerFor();
            // GP
            scale = 0.5f;
            power = 1.25f;
			break;
	}

	_unit = UnitList[nUnitId];	
	float _y = _unit->m_cRelPos[nMyIndex].GetY();

	float fMaxDiff = fabsf( cBallPos.GetY() - ( _y * scale ) );
	int nFarThenMe = 0;

	if ( p_cnt > 3 ) {
		// ak su v jednotke viac ako traja hraci, najdalej stoji hrac sa nepriblizuje k k lopte v zmysle y-ovej suradnice
		float fYDiff;

		for( int i = 0; i < p_cnt; ++i ) {
			fYDiff = fabsf( cBallPos.GetY() - ( /*m_cUnits[nUnitId].m_cRelPos[i].GetY()*/ _y * scale ) );

			if ( fYDiff > fMaxDiff ) {
				nFarThenMe++;
			}
		}

		if ( p_cnt < 6 ) {
			if ( nFarThenMe == 0 ) {
				return cRetVal;
			}
		}
		else {
			if ( nFarThenMe <= 1 ) {
				return cRetVal;
			}
		}
	}
	
	_unit = UnitList[nUnitId];	
	_y = _unit->m_cRelPos[nMyIndex].GetY();

	//float diff = cBallPos.GetY() - cOriginPos.GetY();
	float diff = cBallPos.GetY() - ( _y * scale );
	float x_mem = ( ( FIELD_WIDTH - fabsf( diff ) ) / FIELD_WIDTH );
	
	if ( x_mem > FIELD_WIDTH / 2 ) {
		x_mem *= x_mem;
	}
	
	float r =  x_mem * ( fHi - fLow ) + fLow; 
	cRetVal.SetY( (diff * r * power ) + cRetVal.GetY());

	return cRetVal;
}

Point Formation::AdjustDefPositionX( const Point& player_pos, const Point& ball_pos )
{
	Point ret_val;
	ret_val = player_pos;

	// lopta je blizko nasej brany
	if ( ball_pos.GetX() < m_mDefOffset) {
		ret_val.SetX(ball_pos.GetX());

		if ( ret_val.GetX() < ( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS ) ) {
			ret_val.SetX( -FIELD_LENGTH / 2.0f + MIN_BORDER_X_POS );
		}		
		
		return ret_val;
	}
	
	//lopta je blizko superovej brany
	if ( ball_pos.GetX() > ATTACK_AREA ) {
		ret_val.SetX( HALF_FIELD_X_POS - 4.0f );
		ret_val.SetX( ret_val.GetX() + m_mDefOffset - DEFENCE_AREA); 
		return ret_val;
	}

	// lopta na nasej polovici
	if ( ball_pos.GetX() < HALF_FIELD_X_POS ) {
		ret_val.SetX( ball_pos.GetX() - DEF_MIN_X_DIST);

		if ( ret_val.GetX() < (m_mDefOffset)) {
			ret_val.SetX((m_mDefOffset));
		}

		return ret_val;
	}

	// lopta na superovej polovici, ale nie v utocnej oblasti
	ret_val.SetX(ball_pos.GetX() - DEF_MIN_X_DIST - DEFENCE_AREA + m_mDefOffset);

	if ( ret_val.GetX() > ( ( FIELD_LENGTH / 2.0f ) - 4.0f ) ) {
		ret_val.SetX( ( FIELD_LENGTH / 2.0f ) - 4.0f);
	}

	return ret_val;
}

Point Formation::AdjustMidPositionX( const Point& player_pos, const Point& ball_pos )
{
	Point ret_val;
	ret_val = player_pos;

	if ( ball_pos.GetX() < DEFENCE_AREA ) {
		ret_val.SetX( ball_pos.GetX() + MID_DEF_X_DIST );

		if ( ret_val.GetX() < DEFENCE_AREA ) {
			ret_val.SetX( DEFENCE_AREA);
		}

		return ret_val;
	}

	if ( ball_pos.GetX() > ATTACK_AREA ) {
		ret_val.SetX( ball_pos.GetX() + MID_OFF_X_DIST);

		if ( ret_val.GetX() > ATTACK_AREA ) {
			ret_val.SetX( ATTACK_AREA );
		}

		return ret_val;
	}

// TODO
// GP OffenseMidfielders - bool -  agresivni strednopoliari 
/*
	if ( PlayerConfig.OffenseMidfielders() ) {
		float k = ( -MID_MAX_X_DIST - MID_MAX_X_DIST ) / ( ATTACK_AREA - DEFENCE_AREA );
		ret_val.GetX() = ball_pos.GetX() + MID_MAX_X_DIST + k * ( ball_pos.GetX() - DEFENCE_AREA );
	}
	else {
*/
		const float k = ( MID_OFF_X_DIST - MID_DEF_X_DIST ) / ( ATTACK_AREA - DEFENCE_AREA );
		ret_val.SetX( ball_pos.GetX() + k * ( ball_pos.GetX() - DEFENCE_AREA ) + MID_DEF_X_DIST);
//	}

	return ret_val;
}

Point Formation::AdjustForPositionX( const Point& player_pos, const Point& ball_pos )
{
	float min_dst;
	float max_dst;

	// super ma loptu, tvarme sa ze super ma loptu
	min_dst = FOR_MIN_X_DIST_THEIR;
	max_dst = FOR_MAX_X_DIST_THEIR;

	Point ret_val;
	ret_val = player_pos;

	float k = ( min_dst - max_dst  ) / ( ATTACK_AREA - ( FIELD_LENGTH / 2.0f ) );
	ret_val.SetX( ball_pos.GetX() + k * ( ball_pos.GetX() )  + max_dst);

	if ( fabsf( ret_val.GetX() - ball_pos.GetX() ) > max_dst ) {
		ret_val.SetX(ball_pos.GetX() + max_dst);
	}

	// stred ihriska nech utocnici neprekracuju 
	if ( ret_val.GetX() < FOR_MAX_DEFENCE_X_POS ) {
		ret_val.SetX(HALF_FIELD_X_POS);
		return ret_val;
	}
	
	if ( fabsf( ret_val.GetX() - ball_pos.GetX() ) < min_dst ) {
		ret_val.SetX( ball_pos.GetX() + min_dst);
	}

	if ( ret_val.GetX() > ( FIELD_LENGTH / 2.0f - 10.0f ) ) {
		ret_val.SetX(( FIELD_LENGTH / 2.0f - 10.0f ));
	}

	return ret_val;
}

Formation::~Formation()
{
	int i;
	Unit * _unit;

	for(i = 0; i < 100; i++)
	{
		_unit = UnitList[i];

// TU NIEKDE MAL ZAJAC BUG, HRACI PADALI AKO MUCHY		
// Zatial to riesim nasledovnym riadkom:
//		if(_unit != NULL) delete _unit;
// Asi moze byt i max. 26		
		
//		delete _unit;
	}
}
